package pi.client.network;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import pi.client.board.Board;
import pi.client.core.MyGame;
import pi.client.core.MyProgram;
import pi.client.players.Player;
import pi.client.units.UnitBase;

public class ClientNetwork {
	private MyProgram program;

	private Thread network;

	public boolean connected;

	Socket socket;

	private InputStream inputStream;
	private OutputStream outputStream;
	private InputStreamReader inputStreamReader;
	private OutputStreamWriter outputStreamWriter;
	private BufferedReader in;
	private BufferedWriter out;

	public String lastReceivedData;
	public int serverSize;

	public ClientNetwork(MyProgram program) {
		this.program = program;
		connected = false;
		lastReceivedData = "";
	}

	public void StartNetworking() {
		network = new Thread(new Runnable() {
			@Override
			public void run() {
				MainLoop();
			}
		});
		network.start();
	}

	private void MainLoop() {
		while (connected) {
			ListenServer();
		}
	}

	private void ListenServer() {
		try {
			lastReceivedData = in.readLine();
			ProcessServerProtocol(lastReceivedData);
		} catch (IOException e) {
			e.printStackTrace();
			RequestExitFromServer();
		}
	}

	public boolean ConnectToServer(String hostName, int port) {
		try {
			socket = new Socket(hostName, port);

			inputStream = socket.getInputStream();
			outputStream = socket.getOutputStream();
			inputStreamReader = new InputStreamReader(inputStream);
			outputStreamWriter = new OutputStreamWriter(outputStream);

			in = new BufferedReader(inputStreamReader);
			out = new BufferedWriter(outputStreamWriter);

			SetConnection(true);
			return true;
		} catch (UnknownHostException e) {
			e.printStackTrace();

			SetConnection(false);
			return false;

		} catch (IOException e) {
			e.printStackTrace();

			SetConnection(false);
			return false;
		}
	}

	public void SetConnection(boolean connected) {
		this.connected = connected;
		program.mainPanel.playerMe.isConnected = connected;
	}

	public void RequestExitFromServer() {
		SendMessageToServer("/exit");
	}

	public void RequestServerSize() {
		SendMessageToServer("/serverSize");
	}

	public void RequestServerMapType() {
		SendMessageToServer("/serverMapType");
	}

	public void RequestEnemyUnitsData() {
		SendMessageToServer("/enemyUnitsData");
	}

	//TODO 1
	//TODO FAZER FUNCAO PARA PEGAR AS VIDAS DAS MINHAS UNIDADES QUE ESTAO NO SERVIDOR E APLICAR AO LOCAL.
	public void RequestAllMeUnitsDataOfLastTurn(){
		SendMessageToServer("/meAllUnitsDataByTrn");
	}
	
	//TODO 2
	//TODO FAZER FUNCAO PARA REGISTRAR VIDA DAS UNIDADES DO INIMIGO QUE ESTAO LOCAL, NO SERVIDOR.
	public void RegisterAllEnemyUnitOnMyEndTurn() {
		Player enemy = program.mainPanel.playerEnemy;

		SendMessageToServer("/enemyUnitDataByTurn "
				+ RegisterMyUnitOnMyEndTurn(enemy.unit1) + "v"
				+ RegisterMyUnitOnMyEndTurn(enemy.unit2) + "v"
				+ RegisterMyUnitOnMyEndTurn(enemy.unit3) + "v"
				+ RegisterMyUnitOnMyEndTurn(enemy.unit4) + "v"
				+ RegisterMyUnitOnMyEndTurn(enemy.unit5));
	}
	
	public void RequestAllEnemyUnitsDataOfLastTurn() {
		SendMessageToServer("/enemyAllUnitsDataByTrn");
	}

	public void RequestIsEnemyTurn() {
		SendMessageToServer("/enemyTurn");
	}

	public void RequestEnemyIdData() {
		SendMessageToServer("/enemyIdData");
	}

	public void RequestEnemyNameData() {
		SendMessageToServer("/enemyNameData");
	}

	public void RegisterName() {
		SendMessageToServer("/name " + program.mainPanel.playerMe.username);
	}

	public void RegisterMyUnits() {
		SendMessageToServer("/myUnits " + program.mainPanel.playerMe.unit1.type
				+ "u" + program.mainPanel.playerMe.unit2.type + "u"
				+ program.mainPanel.playerMe.unit3.type + "u"
				+ program.mainPanel.playerMe.unit4.type + "u"
				+ program.mainPanel.playerMe.unit5.type);
	}

	private String RegisterMyUnitOnMyEndTurn(UnitBase unit) {
		String command = unit.x + "u" + unit.y + "u" + unit.life;
		return command;
	}

	public void RegisterAllMyUnitOnMyEndTurn() {
		Player me = program.mainPanel.playerMe;

		SendMessageToServer("/myUnitDataByTurn "
				+ RegisterMyUnitOnMyEndTurn(me.unit1) + "v"
				+ RegisterMyUnitOnMyEndTurn(me.unit2) + "v"
				+ RegisterMyUnitOnMyEndTurn(me.unit3) + "v"
				+ RegisterMyUnitOnMyEndTurn(me.unit4) + "v"
				+ RegisterMyUnitOnMyEndTurn(me.unit5));
	}

	public void RegisterMyTurn(boolean myTurn) {
		SendMessageToServer("/myTurn " + myTurn);
	}

	public void SendMessageToServer(String message) {
		try {
			out.write(message + "\n");
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
			SetConnection(false);
		}
	}

	private void ProcessServerProtocol(String receivedData) {
		if (receivedData != null) {
			boolean isProtocolCommand = receivedData.startsWith("#");

			if (isProtocolCommand == true) {
				Player me = program.mainPanel.playerMe;
				Player enemy = program.mainPanel.playerEnemy;
				Board b = program.mainPanel.board;

				String commandString = receivedData.substring(1);
				String receivedDataList[] = commandString.split(" ");
				String commandStringResult = "";
				commandString = receivedDataList[0];

				if (receivedDataList.length == 1) {

				} else if (receivedDataList.length == 2) {
					commandStringResult = receivedDataList[1];

					// player me
					if (commandString.equalsIgnoreCase("idOnServer")) {
						me.idOnServer = Integer.parseInt(commandStringResult);
					} else if (commandString.equalsIgnoreCase("myTurn")) {
						me.isMyTurn = Boolean.parseBoolean(commandStringResult);
					} else if (commandString.equalsIgnoreCase("nameOnServer")) {
						me.username = commandStringResult;
					} else if (commandString.equalsIgnoreCase("serverKickMe")) {
						MyGame g = program.game;
						if (g != null) {
							g.EndGame(program.mainPanel.preGamePanel);
						}
						// program.mainPanel.playerMe.isConnected = false;
						// program.mainPanel.playerMe.isWinner = false;
						// program.mainPanel.playerMe.isMyTurn = false;
						//
						// program.mainPanel.playerEnemy.isConnected = false;
						// program.mainPanel.playerEnemy.isWinner = false;
						// program.mainPanel.playerEnemy.isMyTurn = false;

						// server
					} else if (commandString.equalsIgnoreCase("serverSize")) {
						serverSize = Integer.parseInt(commandStringResult);
					} else if (commandString.equalsIgnoreCase("serverMapType")) {
						b.RefreshMapByType(Integer
								.parseInt(commandStringResult));
					} else if (commandString.equalsIgnoreCase("exit")) {
						SetConnection(Boolean.parseBoolean(commandStringResult));

						// player me
						//TODO 1 
					} else if (commandString
							.equalsIgnoreCase("meAllUnitsDataByTrn")) {
						String temp[] = receivedData.split(" ");						
						String units[] = temp[1].split("v");
						for (int i = 0; i < units.length; i++) {
							String currentUnit[] = units[i].split("u");

							int x = Integer.parseInt(currentUnit[0]);
							int y = Integer.parseInt(currentUnit[1]);
							int life = Integer.parseInt(currentUnit[2]);
						
							if (x >= 0 && y >= 0) {
								switch (i) {
								case 0:// unit1
									if(me.unit1.x != x || me.unit1.y != y){
										b.MoveUnitToAnotherCell(x, y, me.unit1);
									}
									me.unit1.life = life;
									System.out.println("meAllUnitsDataByTrn unit1 movendo pra x: " + x + " | y: " + y + " | com life: " + life);
									break;
								case 1:// unit2
									if(me.unit2.x != x || me.unit2.y != y){
										b.MoveUnitToAnotherCell(x, y, me.unit2);
									}
									me.unit2.life = life;
									System.out.println("meAllUnitsDataByTrn unit2 movendo pra x: " + x + " | y: " + y + " | com life: " + life);
									break;
								case 2:// unit3
									if(me.unit3.x != x || me.unit3.y != y){
										b.MoveUnitToAnotherCell(x, y, me.unit3);
									}
									me.unit3.life = life;
									System.out.println("meAllUnitsDataByTrn unit3 movendo pra x: " + x + " | y: " + y + " | com life: " + life);
									break;
								case 3:// unit4
									if(me.unit4.x != x || me.unit4.y != y){
										b.MoveUnitToAnotherCell(x, y, me.unit4);
									}
									me.unit4.life = life;
									System.out.println("meAllUnitsDataByTrn unit4 movendo pra x: " + x + " | y: " + y + " | com life: " + life);
									break;
								case 4:// unit5
									if(me.unit5.x != x || me.unit5.y != y){
										b.MoveUnitToAnotherCell(x, y, me.unit5);
									}
									me.unit5.life = life;
									System.out.println("meAllUnitsDataByTrn unit5 movendo pra x: " + x + " | y: " + y + " | com life: " + life);
									break;
								}
							}
						}

						// player enemy
					} else if (commandString.equalsIgnoreCase("enemyDataId")) {
						enemy.idOnServer = Integer
								.parseInt(commandStringResult);
					} else if (commandString.equalsIgnoreCase("enemyDataName")) {
						enemy.username = commandStringResult;
						enemy.isConnected = true;
					} else if (commandString.equalsIgnoreCase("enemyTurn")) {
						MyGame g = program.game;

						if (g != null) {
							g.endTurnTimerCount = 0;
							me.isMyTurn = !Boolean
									.parseBoolean(commandStringResult);
							enemy.isMyTurn = Boolean
									.parseBoolean(commandStringResult);
						}
					} else if (commandString.equalsIgnoreCase("enemyUnitsData")) {
						String unitsIds[] = commandStringResult.split("u");
						int unitsLengh = unitsIds.length;

						int units[] = new int[unitsLengh];
						for (int i = 0; i < unitsLengh; i++) {
							units[i] = Integer.parseInt(unitsIds[i]);
						}

						int currentColumn = 9;
						if (me.idOnServer < enemy.idOnServer) {
							enemy.CreateUnits(units[0], currentColumn, 1,
									units[1], currentColumn, 2, units[2],
									currentColumn, 3, units[3], currentColumn,
									4, units[4], currentColumn, 5);
						} else {
							currentColumn = 0;
							enemy.CreateUnits(units[0], currentColumn, 1,
									units[1], currentColumn, 2, units[2],
									currentColumn, 3, units[3], currentColumn,
									4, units[4], currentColumn, 5);

							me.MoveAllUnitsOnGameStart(9, 1);
						}
					} else if (commandString
							.equalsIgnoreCase("enemyAllUnitsDataByTrn")) {
						String temp[] = receivedData.split(" ");						
						String units[] = temp[1].split("v");
						for (int i = 0; i < units.length; i++) {
							String currentUnit[] = units[i].split("u");

							int x = Integer.parseInt(currentUnit[0]);
							int y = Integer.parseInt(currentUnit[1]);
							int life = Integer.parseInt(currentUnit[2]);
						
							if (x >= 0 && y >= 0) {
								switch (i) {
								case 0:// unit1
									if(enemy.unit1.x != x || enemy.unit1.y != y){
										b.MoveUnitToAnotherCell(x, y, enemy.unit1);
									}
									enemy.unit1.life = life;
									break;
								case 1:// unit2
									if(enemy.unit2.x != x || enemy.unit2.y != y){
										b.MoveUnitToAnotherCell(x, y, enemy.unit2);
									}
									enemy.unit2.life = life;
									break;
								case 2:// unit3
									if(enemy.unit3.x != x || enemy.unit3.y != y){
										b.MoveUnitToAnotherCell(x, y, enemy.unit3);
									}
									enemy.unit3.life = life;
									break;
								case 3:// unit4
									if(enemy.unit4.x != x || enemy.unit4.y != y){
										b.MoveUnitToAnotherCell(x, y, enemy.unit4);
									}
									enemy.unit4.life = life;
									break;
								case 4:// unit5
									if(enemy.unit5.x != x || enemy.unit5.y != y){
										b.MoveUnitToAnotherCell(x, y, enemy.unit5);
									}
									enemy.unit5.life = life;
									break;
								}
							}
						}
					}
				}
			}
			// System.out.println("Recebido do server: " + receivedData);
		}
	}
}